In a computer system, compatibility between various components, both hardware and software, of the system may be important. A new component or an upgrade of an existing component may be incompatible with other components in a system, rendering the entire system inaccurate or inoperative. Thus, it is important to have a mechanism for verifying compatibility between components of a system.
Compatibility plays an important role in a client-provider relationship wherein a provider supplies services to a client because it is important that the provider be able to satisfy expectations of the client. A client-provider relationship may exist between two computer software programs, two computer hardware components or between a software program and a hardware component. An example of a client-provider relationship is a relationship between a shared library (provider), that is a collection of routines which can be accessed by other computer programs, and a computer program (client) which accesses the routines in the library.
Typically, as computer programs are modified, upgraded or otherwise improved, new versions of the computer programs are released. To differentiate between different versions of a computer program, a version number is typically assigned to each release of the computer program. Usually, version numbers are assigned such that a newer version of a computer program has a higher version number than an earlier version of that computer program. For example, if a particular version of a computer program has a version number of 2, then a subsequent version of that computer program may have a version number greater than 2.
Computer programs are typically written originally in source code in a computer language such as C or Pascal, or in an assembly language. To prepare the program for execution on a computer system, a compiler (or assembler ) converts one or more source code modules into an object code file. A compiler (or assembler) is specific to the language used and the computer system on which it will be executed. A linker routine, which is either a separate program or is part of the compiler, combines the object code files into a single output file, known as an "executable" object code file. One or more executables are then loaded together into memory by a loader program, and control is transferred to a start address to initiate program execution.
Typically, in a client-provider relationship between two software programs, it is important for compatibility to exist between the version of a provider such as a shared library linked to a client and the version of the provider (shared library) used during execution of the client. During linking in a client/provider relationship, imports (unresolved external symbols in the client) are resolved to exports from the provider (symbols in the provider that are visible to the client). At link time, the provider supplies definitions of symbols (the API) but not the actual implementation of routines and variables (the code). Thus, the version of the provider used at link time is called a "definition version".
When a client is executed, the imports in the client are connected to the associated exports in the provider. The connection could be in hardware such as a wire between the two, or in software such as an operating system, a code fragment manager, or other shared library or code manager. At runtime, the provider supplies actual implementation of routines and variables, i.e. code. Since the API is supplied at link time and the code is supplied at runtime, it is important that the definitions supplied by a provider at link time are compatible with the implementation of the provider used at runtime.
In the VMS operating system by Digital Equipment Corp., Inc., typically a version of a provider is designed to be compatible with previous versions, i.e. a version of a provider is backwards compatible. VMS is a trademark of Digital Equipment Corporation. Thus, a client can be executed using a version of the provider which is newer than the version with which it was built. However, a version of the provider which is older than the version used to build the client may not support features available in newer versions of the provider. Therefore, a client can not be executed using a version of a provider which is older than the version used to build the client, because the older provider may not be compatible with the newer version.
In VMS, as shown in "VAX/VMS Internals and Data Structures", version 4.4, Lawrence J. Kenah, Ruth E. Goldberg, Simon F. Bate (Digital Press: 1988), section 21.1.1.2, a provider typically has a revision number comprising a major number component and a minor component, usually denoted as "major.minor" or "major/minor". VAX is a trademark of Digital Equipment Corporation. When a new revision of a provider contains substantial changes from a prior instance of the provider, then the major number is incremented. However, if the changes are only minor changes, then usually only the minor number is incremented. At link time, the revision number of the provider supplying the definitions is stored in the executable object code. At execution time, the major number of the stored revision number in the client is compared to the major number in the revision code of the provider being accessed to implement the client. If the major number of the revision of the implementation provider is less than the major number of the revision number stored in the client's executable object code, then the client and provider are considered incompatible, regardless of whether the two are in fact incompatible.
For example, if the client is linked with a provider having a revision number of 7.1, then it would be considered incompatible with a provider having a major number less than 7 such as 6.5, 5.0, etc. . . . , but it would be considered compatible with a provider having a major number greater than or equal to 7 such as 7.5, 8.0, etc. . . . .
The backwards compatibility scheme in VMS presents several problems. First, it discourages a developer of a provider from assigning to a current version of the provider being developed a major number higher than that assigned to the prior version, even though that version may be substantially different from prior versions of the provider.
Second, in this versioning scheme it is usually desirable to use the newest version of an operating system to utilize features or enhancements unavailable in previous versions. However, the newest version of an operating system is usually compatible with the newest version of a shared library and not compatible with older versions of the shared library. Therefore, clients which were built using newer versions of the shared library on a developer's system can not be executed using the older version of the shared library on an end user's system. Thus, developers are encouraged to maintain old system installations in order to link with the oldest available version of a provider, thereby increasing the number of versions of the provider with which it is compatible. Moreover, older versions of the shared library might be retained just to execute clients which were built with older versions of the shared library. These older versions occupy memory space which might otherwise be available for other purposes.
For example, consider a situation where two versions of a provider are available at link time, an earlier version having a version number of 2.0 and a later version having a version number of 4.2. The 4.2 version has some features which are not present in the 2.0 version and which would be advantageous to the client to use. In order to utilize the advantageous features, it is preferable to link with the 4.2 version. However, since it is unknown which version of a provider will be available at runtime, it is also preferable to link with the version with the most likelihood of being compatible with a version available at runtime. In this case, since version 2.0 is compatible with versions greater than or equal to 2.0 and 4.2 is compatible with versions greater than or equal to 4.2, version 2.0 is more likely to be compatible with an available version of a provider than the 4.2 version. Thus, in this case, a client has a choice between either utilizing the advantageous features of the 4.2 version or increasing likelihood of compatibility with 2.0. By choosing to increase the likelihood of compatibility at runtime and thus, linking with the earliest version of a provider available, a client foregoes the advantageous features of later versions of that provider which are also available and which, may, in fact, be compatible with those earlier versions.
In other operating systems such as OS/2, as discussed in "Inside OS/2", Gordon Letwin, (Microsoft Press: 1988), section 7.11.3, and Windows, version numbers are not used for providers such as shared libraries. OS/2 is a registered trademark of Internation Business Machines Corporation. In these systems, older versions are designed to be compatible with newer versions and newer versions are designed to be compatible with older versions. In other words, a version of a provider is designed to be backwards and upwards compatible with other versions of that provider. This places a burden on developers of the shared library to maintain compatibility even when the changes are extensive and even when the older versions may only be used infrequently.